package cn.bugstack.wrench.dynamic.config.center.config;

import cn.bugstack.wrench.dynamic.config.center.listener.DynamicConfigCenterAdjustListener;
import cn.bugstack.wrench.dynamic.config.center.model.valobj.AttributeVO;
import cn.bugstack.wrench.dynamic.config.center.service.DynamicConfigCenterService;
import cn.bugstack.wrench.dynamic.config.center.service.IDynamicConfigCenterService;
import cn.bugstack.wrench.dynamic.config.center.types.common.Constants;
import org.redisson.Redisson;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 负责整个动态配置中心的自动装配。它通过 @Bean 注解分别初始化 Redisson 客户端（用于与 Redis 通信）、
 动态配置中心服务（封装属性的动态获取与变更）、属性变更监听器（监听配置变更事件），
 以及 Redis 发布订阅主题（实现分布式属性变更的消息推送与监听）。这样保证了组件引入后即可自动完成所有依赖的初始化和注册。
 * @author chenjia
 */
@Configuration
//@EnableConfigurationProperties({...})的作用是让指定的 @ConfigurationProperties 类生效并注册为 Bean，这样它们就能从配置文件中读取到对应的配置值。
@EnableConfigurationProperties(value = {
        DynamicConfigCenterAutoProperties.class,
        DynamicConfigCenterRegisterAutoProperties.class})
public class DynamicConfigCenterRegisterAutoConfig {

    private final Logger logger = LoggerFactory.getLogger(DynamicConfigCenterRegisterAutoConfig.class.getName());

    /**
     * 初始化 RedissonClient，作为与 Redis 通信的核心组件。
     * @param properties 动态配置中心Redis配置文件
     * @return RedissonClient
     */
    @Bean("cjWrenchRedissonClient")
    public RedissonClient redissonClient(DynamicConfigCenterRegisterAutoProperties properties) {
        Config config = new Config();
        config.setCodec(JsonJacksonCodec.INSTANCE);
        config.useSingleServer()
                .setAddress("redis://" + properties.getHost() + ":" + properties.getPort())
                .setPassword(properties.getPassword())
                .setConnectionPoolSize(properties.getPoolSize())
                .setConnectionMinimumIdleSize(properties.getMinIdleSize())
                .setIdleConnectionTimeout(properties.getIdleTimeout())
                .setConnectTimeout(properties.getConnectTimeout())
                .setRetryAttempts(properties.getRetryAttempts())
                .setRetryInterval(properties.getRetryInterval())
                .setPingConnectionInterval(properties.getPingInterval())
                .setKeepAlive(properties.isKeepAlive());
        RedissonClient redissonClient = Redisson.create(config);

        logger.info("xfg-wrench，注册器（redis）链接初始化完成。{} {} {}", properties.getHost(), properties.getPoolSize(), !redissonClient.isShutdown());

        return redissonClient;
    }


    /**
     * 自动装配 IDynamicConfigCenterService，用于处理属性的动态获取与变更。
     * @param properties 动态配置中心配置文件
     * @param redissonClient redissonClient
     * @return 动态配置中心服务接口
     */
    @Bean
    public IDynamicConfigCenterService dynamicConfigCenterService(DynamicConfigCenterAutoProperties properties, RedissonClient redissonClient){
        return new DynamicConfigCenterService(properties,redissonClient);
    }

    /**
     * 注册 DynamicConfigCenterAdjustListener，监听配置变更事件。
     * @param dynamicConfigCenterService 动态配置中心服务接口
     * @return DynamicConfigCenterAdjustListener
     */
    @Bean
    public DynamicConfigCenterAdjustListener dynamicConfigCenterAdjustListener(IDynamicConfigCenterService dynamicConfigCenterService){
        return new DynamicConfigCenterAdjustListener(dynamicConfigCenterService);
    }


    /**
     * 使用 Redisson 的 RTopic 功能订阅 Redis 中的动态配置主题，
     * 用于在分布式环境下监听配置属性（AttributeVO）的变更消息。
     * 当有新的属性变更消息发布到该主题时，
     * {@link DynamicConfigCenterAdjustListener} 会自动接收到并执行相应的处理逻辑。
     *
     * @param dynamicConfigCenterAutoProperties 动态配置中心的配置信息（用于确定 Redis 主题名）
     * @param redissonClient                    Redisson 客户端，用于连接 Redis 并订阅主题
     * @param adjustListener                    动态配置属性调整监听器，处理属性变更事件
     * @return RTopic 对象，表示当前注册监听的 Redis 主题
     */
    @Bean(name = "dynamicConfigCenterRedisTopic")
    public RTopic threadPoolConfigAdjustListener(DynamicConfigCenterAutoProperties dynamicConfigCenterAutoProperties,
                                                 RedissonClient redissonClient,
                                                 DynamicConfigCenterAdjustListener adjustListener) {
        RTopic topic = redissonClient.getTopic(Constants.getTopic(dynamicConfigCenterAutoProperties.getSystem()));
        topic.addListener(AttributeVO.class, adjustListener);
        return topic;
    }

}
